''' <summary>
''' This is a game component that implements IUpdateable.
''' </summary>
Public Class GameRun
    Inherits Microsoft.Xna.Framework.DrawableGameComponent
    Implements IGameProto
    Public Event ReloadTitle()
    Private WithEvents Level As GameLevel
    Private WithEvents Ball As ball
    Private WithEvents Controls As overlay
    Private WithEvents SEState As StartEndStates
    Private cLocation As Vector3
    Private LevelData As GameItems
    Private Parent As Game1
    Private mIntLevel As Byte
    Private mblnLevelStarted As Boolean = False
    Public Property Effect As BasicEffect Implements IGameProto.Effect

    ' ////////////////////////////////////////////////////////////////
    ' Returns the camera prosition, used by the components
    Public ReadOnly Property CameraPosition As Vector3 Implements IGameProto.CameraPosition
        Get
            Return cLocation
        End Get
    End Property
    ' ////////////////////////////////////////////////////////////////
    ' Unit size property
    Public ReadOnly Property UnitSize As Single Implements IGameProto.UnitSize
        Get
            Return LevelData.UnitSize
        End Get
    End Property
    Public Sub New(ByVal game As Game, ByVal intLevel As Byte)
        MyBase.New(game)
        ' Load the content components and add them to the main game component list
        mIntLevel = intLevel
        Level = New GameLevel(game, Me)
        Ball = New ball(game, Me)
        Controls = New overlay(game, Me)
        SEState = New StartEndStates(game)
        game.Components.Add(Level)
        game.Components.Add(Ball)
        game.Components.Add(Controls)
        game.Components.Add(SEState)
        Level.DrawOrder = 2
        Ball.DrawOrder = 3
        Controls.DrawOrder = 4
        SEState.DrawOrder = 5

        ' Get a real Game1 Copy of the Game Library
        Parent = CType(game, Game1)
    End Sub
    Public Overrides Sub Initialize()
        ' TODO: Add your initialization code here
        MyBase.Initialize()
    End Sub
    ' ////////////////////////////////////////////////////////////////////////////////////////
    ' Load the specified level
    Public Sub LoadLevel(ByVal intLevelNumber As Byte)
        LevelData.Level = intLevelNumber
        Level.LoadLevel(LevelData.FileName)
        Controls.Time = LevelData.LevelTime
        Controls.Jumps = LevelData.Jumps
        ' Set up the camera
        cLocation = New Vector3(CSng(LevelData.UnitSize * 2.5), LevelData.UnitSize * 3, -LevelData.UnitSize)
        Parent.Camera.Position = cLocation
        Parent.Camera.LookAt = New Vector3(CSng(LevelData.UnitSize * 2.5), -LevelData.UnitSize * 3, LevelData.UnitSize * 8)
        Parent.Camera.ViewNear = LevelData.UnitSize
        Parent.Camera.ViewFar = LevelData.UnitSize * Level.RowCount
        ' Scale the ball from Size 1 to our scale.
        Dim Scaler As Single = CSng(LevelData.UnitSize * 0.3)
        Ball.Scale = New Vector3(Scaler, Scaler, Scaler)
        Ball.Location = New Vector3(CSng(LevelData.UnitSize * 2.5), Scaler, LevelData.UnitSize)
        LevelData.LevelEnded = False
        mblnLevelStarted = False
        LevelData.BottomCamera()
    End Sub
    ' ////////////////////////////////////////////////////////////////////////////////////////
    ' Content Loader
    Protected Overrides Sub LoadContent()
        ' Load the level information
        LevelData = New GameItems(Game)
        ' Load the level and set up the paliminary varibales in the game items
        Level.RowCount = 30
        LoadLevel(mIntLevel)
        ' Set up the renderer
        Effect = New BasicEffect(GraphicsDevice)
        Effect.World = Matrix.Identity
        Effect.FogEnabled = True
        Effect.FogColor = New Vector3(0, 0, 0)
        Effect.FogEnd = LevelData.UnitSize * Level.RowCount
        Effect.FogStart = LevelData.UnitSize * 4
        Effect.View = Parent.Camera.View
        Effect.Projection = Parent.Camera.Projection
        Effect.VertexColorEnabled = True
        MyBase.LoadContent()
    End Sub
    ' ////////////////////////////////////////////////////////////////////////////////////////
    ' kill all the crap
    Protected Overrides Sub UnloadContent()
        MyBase.UnloadContent()
        Game.Components.Remove(Level)
        Game.Components.Remove(Ball)
        Game.Components.Remove(Controls)
        Game.Components.Remove(SEState)
        Level = Nothing
        Ball = Nothing
        Controls = Nothing
        SEState = Nothing
    End Sub
    ' ////////////////////////////////////////////////////////////////////////////////////////
    ' Update as Required
    Public Overrides Sub Update(ByVal gameTime As GameTime)
        If (Not mblnLevelStarted) Then
            SEState.ReadyGo()
        End If
        If (Not LevelData.LevelEnded And mblnLevelStarted) Then
            ' Check if we need to alter the speed (depending on the square we're on)
            Dim cCell As Color = Level.CheckSquare(Ball.Location)
            If (Not Ball.IsJumping And Not Ball.IsFalling) Then
                Select Case cCell
                    Case JumpType.Normal1, JumpType.Normal2, JumpType.Normal3, JumpType.Normal4, JumpType.Hole, JumpType.Reverse, JumpType.Stuck
                        LevelData.SpeedMultiplier = 1
                    Case JumpType.Slow
                        LevelData.SpeedMultiplier = 0.5
                    Case JumpType.Fast
                        LevelData.SpeedMultiplier = 2.0
                End Select
                ' Direction?
                Select Case cCell
                    Case JumpType.Reverse
                        LevelData.Direction = -1
                    Case JumpType.Stuck
                        LevelData.Direction = 0
                    Case Else
                        If (Not Ball.IsJumping And Not cCell = JumpType.Jump) Then
                            LevelData.Direction = 1
                        End If
                End Select
                ' Jump
                If (cCell = JumpType.Jump) Then
                    Ball.Jump()
                End If
                ' Falling?
                If (cCell = JumpType.Hole) Then
                    Ball.Fall(LevelData.Speed * LevelData.SpeedMultiplier)
                    LevelData.SpeedMultiplier = 0
                End If
            End If
            If (Not Ball.IsFalling And LevelData.SpeedMultiplier = 0 And cCell = JumpType.Hole) Then
                LevelData.SpeedMultiplier = 1
                LevelData.Direction = 1
            End If
            ' Move the camera and the ball
            cLocation.Z += LevelData.Speed * LevelData.SpeedMultiplier
            Ball.LocationZ += LevelData.Speed * LevelData.SpeedMultiplier
            Ball.RotateZ -= LevelData.Speed * LevelData.SpeedMultiplier
            Controls.Score += CInt(LevelData.ScoreIncrease * LevelData.SpeedMultiplier)
        End If
        If (mblnLevelStarted) Then
            If (LevelData.SpeedMultiplier = 1) Then
                LevelData.ReduceCamera()
            ElseIf (LevelData.SpeedMultiplier < 1) Then
                LevelData.SlowCamera()
            Else
                LevelData.SpeedCamera()
            End If
        End If
        If (LevelData.CameraSpeedIncrement <> 0) Then
            Parent.Camera.Position = New Vector3(cLocation.X, cLocation.Y, cLocation.Z - LevelData.CameraSpeedIncrement)
        Else
            Parent.Camera.Position = cLocation
        End If
        Parent.Camera.LookAt = New Vector3(CSng(LevelData.UnitSize * 2.5 + (cLocation.X - CSng(LevelData.UnitSize * 2.5)) / 1.2), -CSng(LevelData.UnitSize * 1.5), CSng(cLocation.Z + LevelData.UnitSize * 6 + LevelData.CameraSpeedIncrement / 3.0))
        Effect.View = Parent.Camera.View
        ' TODO: Add your update code here
        MyBase.Update(gameTime)
    End Sub
    ' ////////////////////////////////////////////////////////////////
    ' Draw the screen, we don't do anything here since the components handle it but we will record the current renderstate so it can 
    ' be restored after the other components mess with it.
    Public Overrides Sub Draw(gameTime As Microsoft.Xna.Framework.GameTime)
        'LevelData.SetRenderTarget(True)

        'Effect.CurrentTechnique.Passes(0).Apply()

        MyBase.Draw(gameTime)
        'LevelData.SetRenderTarget(False)
    End Sub
    ' ////////////////////////////////////////////////////////////////
    ' End of level.... we should stop and review... then load the next level
    Private Sub Level_EndOfLevel() Handles Level.EndOfLevel
        Controls.StartTime = False
        LevelData.LevelEnded = True
        SEState.EndOfLevel(Controls)
    End Sub
    ' ////////////////////////////////////////////////////////////////
    ' We get the touch events here from the overlay
    Private Sub Controls_ClickedItem(Type As Integer) Handles Controls.ClickedItem
        Dim multiplier As Single = 1
        If (mblnLevelStarted) Then
            If (LevelData.SpeedMultiplier < 1) Then
                multiplier = LevelData.SpeedMultiplier
            End If
            Select Case Type
                Case 1
                    Ball.LocationX += LevelData.MoveSpeed * LevelData.Direction * multiplier
                Case 2
                    Ball.LocationX -= LevelData.MoveSpeed * LevelData.Direction * multiplier
                Case 3
                    If (Not Ball.IsJumping And Not Ball.IsFalling And Controls.Jumps > 0) Then
                        ' Cna't jump if we are stuck.
                        If (Level.CheckSquare(Ball.Location) <> JumpType.Stuck) Then
                            Controls.Jumps -= 1
                            Ball.Jump()
                        End If
                    End If
            End Select
            If (Ball.LocationX < LevelData.UnitSize / 2.0) Then
                Ball.LocationX = CSng(LevelData.UnitSize / 2.0)
            End If
            If (Ball.LocationX > LevelData.UnitSize * 5 - LevelData.UnitSize / 2.0) Then
                Ball.LocationX = CSng(LevelData.UnitSize * 5 - LevelData.UnitSize / 2.0)
            End If
            cLocation.X = Ball.LocationX
        End If
    End Sub
    ' /////////////////////////////////////////////////////////////////
    ' This is fired when the time limit is reduced enought to fail
    Private Sub Controls_TimeEnded() Handles Controls.TimeEnded
        If (Not LevelData.LevelEnded) Then
            LevelData.LevelEnded = True
            LevelData.SpeedMultiplier = 0
            LevelData.TimedOut = True
            SEState.TimeOut()
        End If
    End Sub
    ' /////////////////////////////////////////////////////////////////
    ' We've been asked to open the next level :>
    Private Sub SEState_NextLevel() Handles SEState.NextLevel
        Dim sg As savegame = New savegame
        sg.SetScore(LevelData.Level, Controls.Score)
        sg.SetLevel(LevelData.Level + 1)
        sg.SaveData()
        LoadLevel(CByte(LevelData.Level + 1))
    End Sub
    ' /////////////////////////////////////////////////////////////////
    ' Ready, St, Go has been completed!
    Private Sub SEState_StartCompleted() Handles SEState.StartCompleted
        mblnLevelStarted = True
        Controls.StartTime = True
    End Sub
    ' /////////////////////////////////////////////////////////////////
    ' The games needs to reset since the user ran out of time
    Private Sub SEState_TimeoutCompleted() Handles SEState.TimeoutCompleted
        RaiseEvent ReloadTitle()
    End Sub
End Class
